class TreeNode {
    /**
     * @param {*} [value] - node value.
     */
    constructor(value = null) {
        this.children = null;
        this.parent = null;
        this.value = value;

        // // Any node related meta information may be stored here.
        // this.meta = new HashTable();

        // // This comparator is used to compare binary tree nodes with each other.
        // this.nodeComparator = new Comparator();
    }

    getParent() {
        return this.parent
    }

    getRoot() {
        if (!this.parent) {
            return this
        } else {
            return this.parent.getRoot()
        }
    }

    //找到相应值的节点
    findNodeByValue(value) {
        let root = this.getRoot() //找到root
        let list = root.traverseInOrderByList() //使用root遍历
        let result = null
        list.forEach(node => {
            if (node.value == value) {
                result = node
            }
        });
        return result
    }


    /**
     * @param {*} value
     * @return {TreeNode}
     */
    setValue(value) {
        this.value = value;

        return this;
    }

    /**
     * @param {*} value
     * @return {TreeNode}
     */
    setChildren(children) {
        this.children = children;
        return this;
    }

    addChild(child) {
        if (!this.children) {
            this.children = []
        }
        child.parent = this
        this.children.push(child)
        return [this, child]
    }


    /**
     * @param {TreeNode} node
     * @return {TreeNode}
     */
    insert(node) {
        // Reset parent for left node since it is going to be detached.
        return this.addChild(node)[0]
    }



    /**
     * 将下级节点清空
     */
    removeChild() {
        if (this.children) {
            this.children = null
            return true
        } else {
            return true;
        }
    }

    /**
     * @param {TreeNode} nodeToReplace
     * @param {TreeNode} replacementNode
     * @return {boolean}
     */
    replaceChild(nodeToReplace, replacementNode) {
        if (!nodeToReplace || !replacementNode) {
            return false;
        }

        nodeToReplace.setValue(replacementNode.value)
        nodeToReplace.setChildren(replacementNode.children)

        return true

    }

    /**
     * @param {TreeNode} sourceNode
     * @param {TreeNode} targetNode
     */
    static copyNode(sourceNode, targetNode) {
        targetNode.setValue(sourceNode.value);
        targetNode.setChildren(sourceNode.children)
    }

    /**
     * @return {*[]}
     */
    traverseInOrder() {
        let traverse = [];
        traverse.push(this.value);
        // Add left node.
        if (this.children) {
            let children = this.children
            for (let i = 0; i < children.length; i++) {
                const element = children[i];
                traverse = traverse.concat(element.traverseInOrder());
            }
        }
        return traverse;
    }

    /**
     * @return {*[]}
     */
    traverseInOrderByList() {
        let traverse = [];
        // Add left node.
        if (this.children) {
            let children = this.children

            for (let i = 0; i < children.length; i++) {
                const element = children[i];
                traverse = traverse.concat(element.traverseInOrderByList());
            }

        }
        // Add root.
        traverse.push(this);
        return traverse;
    }

    /**
     * @return {string}
     */
    toString() {
        return this.traverseInOrder().toString();
    }

    isLeaf() {
        if (this.children.length == 0) {
            return true
        } else {
            return false
        }
    }

    getAllLeaf(parentName, holder) {
        let self = this
        let name = ''
        let children = this.children
        if (!children) {
            name = parentName + '.' + this.value.toString()
            console.log(name);
            holder[name] = null
        } else {
            children.forEach(i => {
                if (parentName) {
                    name = parentName + '.' + self.value.toString()
                } else {
                    name = self.value.toString()
                }
                i.getAllLeaf(name, holder)
            });
        }
    }
}
export {TreeNode}